<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>后端学习记录 - 随时随地记录知识</title><meta name="author" content="h0ss"><meta name="copyright" content="h0ss"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="h0ss的后端学习记录">
<meta property="og:type" content="website">
<meta property="og:title" content="后端学习记录">
<meta property="og:url" content="https://blog.gpnusz.cn/page/2/index.html">
<meta property="og:site_name" content="后端学习记录">
<meta property="og:description" content="h0ss的后端学习记录">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://blog.gpnusz.cn/img/avatar.jpg">
<meta property="article:author" content="h0ss">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://blog.gpnusz.cn/img/avatar.jpg"><link rel="shortcut icon" href="/img/favicon.png"><link rel="canonical" href="https://blog.gpnusz.cn/page/2/"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><script>const GLOBAL_CONFIG = { 
  root: '/',
  algolia: undefined,
  localSearch: undefined,
  translate: undefined,
  noticeOutdate: undefined,
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '天',
  date_suffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'fancybox',
  Snackbar: undefined,
  source: {
    jQuery: 'https://cdn.jsdelivr.net/npm/jquery@latest/dist/jquery.min.js',
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/justifiedGallery/dist/js/jquery.justifiedGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/justifiedGallery/dist/css/justifiedGallery.min.css'
    },
    fancybox: {
      js: 'https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.js',
      css: 'https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.css'
    }
  },
  isPhotoFigcaption: false,
  islazyload: false,
  isanchor: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = { 
  isPost: false,
  isHome: true,
  isHighlightShrink: false,
  isToc: false,
  postUpdate: '2022-11-16 01:31:32'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          if (t === 'dark') activateDarkMode()
          else if (t === 'light') activateLightMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    })(window)</script><meta name="generator" content="Hexo 5.4.0"><link rel="stylesheet" href="/css/prism-tomorrow.css" type="text/css"></head><body><div id="web_bg"></div><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="author-avatar"><img class="avatar-img" src="/img/avatar.jpg" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="site-data"><div class="data-item is-center"><div class="data-item-link"><a href="/archives/"><div class="headline">文章</div><div class="length-num">51</div></a></div></div><div class="data-item is-center"><div class="data-item-link"><a href="/tags/"><div class="headline">标签</div><div class="length-num">14</div></a></div></div></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div></div></div><div class="page" id="body-wrap"><header class="not-top-img" id="page-header"><nav id="nav"><span id="blog_name"><a id="site-name" href="/">后端学习记录</a></span><div id="menus"><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div><div id="toggle-menu"><a class="site-page"><i class="fas fa-bars fa-fw"></i></a></div></div></nav></header><main class="layout" id="content-inner"><div class="recent-posts" id="recent-posts"><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2022/06/14/%E3%80%90MySQL%E3%80%91%E6%97%A5%E5%BF%97%E6%96%87%E4%BB%B6%E6%B1%87%E6%80%BB/" title="【MySQL】日志文件汇总">【MySQL】日志文件汇总</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-06-13T17:52:16.000Z" title="发表于 2022-06-14 01:52:16">2022-06-14</time></span></div><div class="content">1、undo logundo log 是 InnoDB 存储引擎的日志，用于保证数据的原子性，其中保存了事务发生之前的数据的一个版本，也就是说记录的是修改之前的数据，可以用于回滚，前面提到的 MVCC 版本链就是连接到这里。
undo log 的主要作用是事务回滚、实现多版本控制(MVCC)。
2、redo logredo log 是 InnoDB 存储引擎所特有的一种日志，用于记录事务操作的变化，记录的是数据修改之后的值，不管事务是否提交都会记录下来(也会记录下事务的 id 信息)，这让使用了 InnoDB 的数据库具有 crash-safe 能力。
当有增删改相关的操作会先写到 redo log 之后更新内存，这样一条更新语句就算完成了，等到 mysql 有空闲的时候再将操作记录更新到磁盘中。
需要注意的是，redo log 日志是有固定大小的，比如可以配置一组4个文件，一个文件1GB，那么总容量就有4GB，等到容量满了就必须先停下来刷盘，之后再进行写入。

正常的实例，数据写入后的最终落盘，是从 redo log 更新过来的还是从 buffer pool 更新过来的呢？
redo ...</div></div></div><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2022/06/12/%E3%80%90MySQL%E3%80%91%E5%B9%BB%E8%AF%BB%E7%9A%84%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/" title="【MySQL】幻读的解决方案">【MySQL】幻读的解决方案</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-06-11T17:05:50.000Z" title="发表于 2022-06-12 01:05:50">2022-06-12</time></span></div><div class="content">幻读指的是在一个事务中查询到其他事务提交的insert记录即可成为幻读，那么在InnoDB中针对幻读也提供了 MVCC 和 Next-Key Lock 来解决。
1、MVCC 解决方案在 RR 隔离级别下仅使用 MVCC 就可以解决快照读下的幻读问题，前面我们也讲到了 MVCC 的原理是创建一个数据视图，之后的查询都依据该视图去查，那么这时候其他事务所做的修改操作其实都不会影响到。
2、Next-Key Lock前面讲的是在快照读的情况下幻读得到了解决，但是在当前读下幻读依旧会存在，因为当前读读取的是最新的数据，意味着其他事务insert的记录也会被读到。
InnoDB中提供了Gap Lock（间隙锁）来解决这个问题，在表中值与值之间会有一个空隙，Gap Lock 就是加在这个空隙区间的，比如这里就产生了7个区间：

间隙锁之间并不会有冲突的问题，跟间隙锁冲突的是“往这个间隙中插入新纪录”的这个操作，例如下面这个例子，预知的是 c=7 是不存在的：

那么对于这两个语句来说，session B 并不会被阻塞住，因为他们两个锁住的都是（5，10）这个区间，而间隙锁本身是不会有冲突的。
间 ...</div></div></div><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2022/06/11/%E3%80%90MySQL%E3%80%91MVCC%E8%AF%A6%E8%A7%A3/" title="【MySQL】MVCC详解">【MySQL】MVCC详解</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-06-10T17:43:25.000Z" title="发表于 2022-06-11 01:43:25">2022-06-11</time></span></div><div class="content">0、MVCC是什么？对于 RC 隔离级别来说，要求不能读到未提交的信息，而对于 RR 隔离级别来说不能出现前后两次读取信息不一致的问题，那么解决方案有两种，一种是直接加锁，保证并发安全，但这种方式的并发度太低了，另一种方式就是使用上 MVCC。
MVCC 全称为多版本并发控制，其中一个重要的概念就是视图，通过多视图形成多版本，并串成一个版本链，从而保证需要的历史信息不被抹除。MVCC 在 InnoDB 中的体现主要依赖于表隐藏字段。
1、隐藏字段和版本链在 InnoDB 中一个表中有三个隐藏字段，其中一个是row_id ，跟 MVCC 关系不大，这里就不展开了，另外两个则是 trx_id 和 roll_pointer。
trx_id 代表的是产生当前行数据的对应的事务id，而事务id是由引擎自动生成的，呈现严格递增的状态， 每个开启的事务都会被分配到一个事务id（只读事务事务id默认为0），当事务对记录进行操作，并产生实质改变时记录trx_id就会更新。
roll_pointer 代表的是事务回滚指针，指向的是上一条记录的undo日志位置，对于一个事务的insert语句创建的记录会执行 ...</div></div></div><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2022/06/09/%E3%80%90MySQL%E3%80%91%E5%90%84%E7%A7%8D%E9%94%81/" title="【MySQL】各种锁">【MySQL】各种锁</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-06-08T18:18:28.000Z" title="发表于 2022-06-09 02:18:28">2022-06-09</time></span></div><div class="content">1、锁的分类① 排他性：排它锁（X锁）、共享锁（S锁）
② 粒度区分：表锁、记录锁（Record）、间隙锁（Gap）【Record和Gap合称Next-Key-Lock】
③ 状态：意向共享锁、意向排它锁
2、锁的使用第一种方式（显示）：
可以在语句中显示指定加锁的类型，比如加读共享锁可以用：SELECT ... LOCK IN SHARE MODE ; 加排它锁可以用：SELECT ... FOR UPDATE;
第二种方式（隐式）：
① DELETE：对于delete语句来说，实际上是找到B+树上的这一行记录并加上一个X锁，接着打上delete mark；
② INSERT：insert语句执行时不会强制上X/S锁，只是会利用一个隐式锁来确保新插入的语句不被其他事务看到；
③ UPDATE：update语句要分成三种情况
第一种：键值未修改且更新列的占用空间未修改的情况下，会给数据加一个X锁，之后再原地修改；
第二种：键值未修改但更新列的占用空间被修改的情况下，会先给数据加一个X锁，之后删除记录，再原地新增一条记录，这时insert就是由隐式锁提供支持了；
第三种：键值被修改的情况 ...</div></div></div><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2022/06/08/%E3%80%90MySQL%E3%80%91%E4%BA%8B%E5%8A%A1ACID%E4%B8%8E%E9%9A%94%E7%A6%BB%E7%BA%A7%E5%88%AB/" title="【MySQL】事务ACID与隔离级别">【MySQL】事务ACID与隔离级别</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-06-07T16:47:19.000Z" title="发表于 2022-06-08 00:47:19">2022-06-08</time></span></div><div class="content">1、AID 与 C原子性（Atomic）：在同一项业务处理过程中，事务保证了对多个数据的修改，要么同时成功，要么同时被撤销。
一致性（Consistency）：保证系统中所有的数据都是符合期望的，且相互关联的数据之间不会产生矛盾。
隔离性（Isolation）：在不同的业务处理过程中，事务保证了各自业务正在读、写的数据互相独立，不会彼此影响。
持久性（Durability）：事务应当保证所有成功被提交的数据修改都能够正确地被持久化，不丢失数据。
实际上依据《凤凰架构》周志明老师的看法，AID是手段，而C是最终要达到的目标，这四个不应该放在一起讨论，但习惯上还是合称它们为ACID，这里也就沿用了这种说法。需要注意到，AD需要由日志来实现，而I是由锁来实现。
2、隔离级别MySQL 中有四种隔离级别，分别为读未提交、读已提交、可重复读、串行化，对应地在不同的隔离级别下可能会产生一些问题，如下表：



隔离级别
脏读
不可重复读
幻读



读未提交
Possible
Possible
Possible


读已提交
Not Possible
Possible
Possible


可重复 ...</div></div></div><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2022/05/09/%E3%80%90Debug%E3%80%91Dubbo%E5%BC%82%E5%B8%B8%E5%A4%84%E7%90%86%E6%8E%92%E9%94%99%E8%AE%B0/" title="【Debug】Dubbo异常处理排错记">【Debug】Dubbo异常处理排错记</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-05-08T18:18:53.000Z" title="发表于 2022-05-09 02:18:53">2022-05-09</time></span></div><div class="content">1）背景：问题出现在近期一个在线教育项目中的登录校验服务，主要分为统一接口模块、服务模块和 API 模块。执行逻辑是这样的：一旦用户调用对应的登录 API 之后，会通过 Dubbo 远程调用到校验服务，之后返回对应的结果。在服务模块中为了方便对业务异常进行处理，使用了自定义的登录异常，这里的逻辑封装在统一实体模块的一个枚举类中，作为外部包导入。
123456789101112131415161718public enum BusinessExceptionCode &#123;    // 在这里声明业务异常    PHONE_NUMBER_EXIST(&quot;手机号已存在&quot;),    STUDENT_NOT_EXIST(&quot;学员不存在&quot;),    LOGIN_FAIL(&quot;登录失败，用户名或密码错误&quot;),    BE_BAN_FAIL(&quot;该账号处于封禁状态，请联系管理员&quot;);    private final String desc;    BusinessExceptionCode(String desc) &# ...</div></div></div><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2022/04/13/%E3%80%90%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88%E3%80%91%E7%BB%86%E8%AF%B4%E5%88%86%E7%89%87%E4%B8%8A%E4%BC%A0%E4%B8%8E%E6%9E%81%E9%80%9F%E7%A7%92%E4%BC%A0-SpringBoot-Vue/" title="【解决方案】细说分片上传与极速秒传(SpringBoot+Vue)">【解决方案】细说分片上传与极速秒传(SpringBoot+Vue)</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-04-12T18:14:36.000Z" title="发表于 2022-04-13 02:14:36">2022-04-13</time></span></div><div class="content">预期目标
  目标：需要突破服务端上传大小限制，实现大视频文件的上传

  预期：大视频文件上传不受上传大小的限制


评估结果要想实现大文件上传有两种方式：
1）调大服务端的文件上传限制：在一定长度上可以缓解上传限制问题，但并不是最优解。一方面无限制地调大上传大小会加大服务端的压力；一方面这个限制值调成多少是个需要考量的问题。
2）假设服务端的限制是10M，需要上传的文件是20M，直接上传显然是不可以的，那么分两次呢？把文件切分到符合限制的大小分批发送，这样就可以突破限制，这也就是分片上传。
下面主要就分片上传的方案做阐述。
分片上传前期准备
首先这里上传功能用antd的上传组件来实现，通过自定义上传动作来完成分片上传；并且做文件切片时需要记录下文件的 md5 信息，以便后续在服务端根据md5值来进行文件合并，这里需要用到spark-md5 库来做文件md5计算，同时使用的 axios 来发起请求，具体依赖如下：



依赖
版本



vue
^3.0.0


ant-design-vue
^2.2.8


axios
^0.24.0


spark-md5
^3.0.2


1、 ...</div></div></div><div class="recent-post-item"><div class="post_cover right_radius"><a href="/2022/03/18/Redis%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-3-%EF%BC%9A%E9%87%8D%E8%A6%81%E7%9F%A5%E8%AF%86%E7%82%B9%E6%95%B4%E5%90%88/" title="Redis学习笔记(3)：重要知识点整合">     <img class="post_bg" src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/c64edeba643847718e4e50b859fcd135~tplv-k3u1fbpfcp-watermark.image" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Redis学习笔记(3)：重要知识点整合"></a></div><div class="recent-post-info"><a class="article-title" href="/2022/03/18/Redis%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-3-%EF%BC%9A%E9%87%8D%E8%A6%81%E7%9F%A5%E8%AF%86%E7%82%B9%E6%95%B4%E5%90%88/" title="Redis学习笔记(3)：重要知识点整合">Redis学习笔记(3)：重要知识点整合</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-03-18T06:57:32.000Z" title="发表于 2022-03-18 14:57:32">2022-03-18</time></span></div><div class="content">7、三种缓存访问方式① 旁路缓存：读取数据时先从redis中读取，如果存在直接返回；如果不存在则访问数据库，将数据写入redis，之后返回；写数据时会先将数据写入数据库中，写入完成之后再删除redis的缓存，下次访问加载的就是最新的数据了。
② 读写穿透：类似旁路缓存，但是读取写入操作不是由客户端来进行逻辑判断的，而是由缓存中间件去完成，当然redis是不具备这样的功能的。
③ 异步写入：数据写入时先写到缓存中，之后再异步地写到数据库，这可能会带来缓存一致性问题，对于一致性要求不高的情况下可以使用【热点排行榜、点赞、阅读量】。
8、数据一致性问题先更新数据库，之后删除缓存，可以很大程度上确保数据一致性【并发情景下】
而不可忽视的是，更新和删除中间可能出现的失败，如果更新数据库成功，但是删除缓存失败也会造成数据不一致的问题，因此这里可以引入消息队列，将删除缓存的任务发送到消息队列中，由指定的消费者去进行，失败就重试。
如果不想在业务层引入消息队列去解决，可以订阅数据库日志(binlog)，接着根据日志的变更去删除对应的缓存信息，这样在业务层就只需要更新数据库，其他的操作可以交给订阅日志的 ...</div></div></div><div class="recent-post-item"><div class="post_cover left_radius"><a href="/2022/02/16/Redis%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-2-%EF%BC%9ARedis%E5%AE%9E%E8%B7%B5%E4%B8%8E%E5%BA%94%E7%94%A8/" title="Redis学习笔记(2)：Redis实践与应用">     <img class="post_bg" src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/dc3ac57fc2e346e0a5efa3710bd96906~tplv-k3u1fbpfcp-watermark.image" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Redis学习笔记(2)：Redis实践与应用"></a></div><div class="recent-post-info"><a class="article-title" href="/2022/02/16/Redis%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-2-%EF%BC%9ARedis%E5%AE%9E%E8%B7%B5%E4%B8%8E%E5%BA%94%E7%94%A8/" title="Redis学习笔记(2)：Redis实践与应用">Redis学习笔记(2)：Redis实践与应用</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-02-16T05:21:13.000Z" title="发表于 2022-02-16 13:21:13">2022-02-16</time></span></div><div class="content">1、分布式锁实现实现一首先考虑使用 setnx 实现键不在加入，键在不加的单对象持有锁功能；
接着考虑程序失败可能导致的锁一直不释放问题，搭配 expire 来实现过期自动删除；
又因为这两个命令执行中间可能出错，不是原子性的，可以使用 set 加上 nx、ex/px 参数来实现原子操作；
实现二如果程序执行太久，而锁过期时间太短，会导致键被删除了，但实际上程序还需要用到该锁，这时可以在持有锁时加入一个随机数，在删除时先判断是否是对应的随机数再进行删除，又因为多条命令的原子性问题，可以引入 Lua 脚本实现多条命令的原子操作；这样只是相对地安全，如果想再提高保障性，则需要引入可重入锁，在锁键过期时该对象再次持有锁，但这种方式实现起来及其复杂。
实现三RedLock(Redis Distributed Lock) 也即是 redis 实现的分布式锁，适用于多节点环境下的分布式锁实现，可以有效防止单点故障导致的锁问题。
这里先明确锁过期时间设为 TTL ，客户端获取锁超时时间为 timeout，时钟漂移为 cd。
首先在客户端发出加锁命令之前会先获取时间戳【用于计算超时时间】，之后依次向多 ...</div></div></div><div class="recent-post-item"><div class="post_cover right_radius"><a href="/2022/02/13/JVM-%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-4-%EF%BC%9A%E5%86%85%E5%AD%98%E5%88%86%E9%85%8D%E4%B8%8E%E5%9B%9E%E6%94%B6%E7%AD%96%E7%95%A5/" title="JVM 学习笔记(4)：内存分配与回收策略">     <img class="post_bg" src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7813639e9d074ab0bcf915615a65e477~tplv-k3u1fbpfcp-watermark.image" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="JVM 学习笔记(4)：内存分配与回收策略"></a></div><div class="recent-post-info"><a class="article-title" href="/2022/02/13/JVM-%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-4-%EF%BC%9A%E5%86%85%E5%AD%98%E5%88%86%E9%85%8D%E4%B8%8E%E5%9B%9E%E6%94%B6%E7%AD%96%E7%95%A5/" title="JVM 学习笔记(4)：内存分配与回收策略">JVM 学习笔记(4)：内存分配与回收策略</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-02-13T13:25:41.000Z" title="发表于 2022-02-13 21:25:41">2022-02-13</time></span></div><div class="content">1、对象优先在 Eden 区分配一般情况下，对象都优先在新生代的 Eden 区中分配，当 Eden 内存不足时将会发起一次 Minor GC。
2、大对象直接进入老年代大对象指的是占用大量连续内存的 Java对象，例如长字符串、长数组等，这些大对象的内存分配可能会遭遇总空间充足但连续空间不足而无法分配的情况，或者在复制对象时产生高昂的成本，因此在 Serial 或者 ParNew 虚拟机中可以使用参数 -XX：PretenureSizeThreshold 来设置大对象的阈值，超过此值会直接进入老年代。
3、长期存活对象进入老年代对于分代收集来说，判断对象进入老年代的依凭是对象的年龄，在对象头中会有标记对象年龄的计数器，对象每在 Survivor 区中熬过一次垃圾收集则年龄加一，当年龄达到阈值时会晋升如老年代中，可以通过参数 -XX： MaxTenuringThreshold 来设置年龄阈值。
4、动态对象年龄判定为了适应内存实际情况，如果在 Survivor 中相同年龄所有对象大小的总和大于 Survivor 的一半，则大于或等于该年龄的对象可以直接进入老年代，无需达到阈值要求。
5、 ...</div></div></div><div class="recent-post-item"><div class="post_cover left_radius"><a href="/2022/02/13/JVM-%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-3-%EF%BC%9AHotSpot-%E7%AE%97%E6%B3%95%E5%AE%9E%E7%8E%B0%E7%9A%84%E7%BB%86%E8%8A%82/" title="JVM 学习笔记(3)：HotSpot 算法实现的细节">     <img class="post_bg" src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/88d53efa82be40ad9320eaab352e3e75~tplv-k3u1fbpfcp-watermark.image" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="JVM 学习笔记(3)：HotSpot 算法实现的细节"></a></div><div class="recent-post-info"><a class="article-title" href="/2022/02/13/JVM-%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-3-%EF%BC%9AHotSpot-%E7%AE%97%E6%B3%95%E5%AE%9E%E7%8E%B0%E7%9A%84%E7%BB%86%E8%8A%82/" title="JVM 学习笔记(3)：HotSpot 算法实现的细节">JVM 学习笔记(3)：HotSpot 算法实现的细节</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-02-13T13:14:02.000Z" title="发表于 2022-02-13 21:14:02">2022-02-13</time></span></div><div class="content">HotSpot 算法实现的细节1、根节点枚举前面讲到了可以作为根节点的对象，但如果需要去遍历寻找这些对象的话成本就太高了，并且这个过程是会造成 STW 的，因此需要一种更高效的枚举手段；
HotSpot 中采用一组 OopMap 数据结构记录对象的引用情况，在类加载完成后 HotSpot 会记录下对象中属性的偏移量和类型，在即时编译阶段会在特定位置记录下对象引用情况，OopMap 就是用来记录这两部分内容的，后面扫描时直接找到这些对象作为 GC Root 即可；
2、安全点实际情况不可能给每个指令都创建一个 OopMap ，只有在特定位置——安全点才会去生成 OopMap，那么如何让用户线程移动到安全点暂停呢？
一种方案是检测到垃圾收集则马上暂停线程，如果有线程不在安全点上则让它继续走到上面再中断，这种方式几乎没有 JVM 在用；
另一种是在安全点处打上标记，线程不断轮询该标记的真假，待该标记为真时，线程走到最近的安全区主动暂停，完成垃圾收集工作之后线程再恢复运行。
这里轮询操作在 HotSpot 中是使用了 内存保护陷阱 方式，如果此时需要暂停用户线程则虚拟机会将轮询指令所在内存页设 ...</div></div></div><div class="recent-post-item"><div class="post_cover right_radius"><a href="/2022/02/10/JVM-%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-2-%EF%BC%9A%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6GC/" title="JVM 学习笔记(2)：垃圾回收GC">     <img class="post_bg" src="https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/3370ec76aafb4bf391c1d6d503abc872~tplv-k3u1fbpfcp-watermark.image" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="JVM 学习笔记(2)：垃圾回收GC"></a></div><div class="recent-post-info"><a class="article-title" href="/2022/02/10/JVM-%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0-2-%EF%BC%9A%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6GC/" title="JVM 学习笔记(2)：垃圾回收GC">JVM 学习笔记(2)：垃圾回收GC</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-02-09T17:52:09.000Z" title="发表于 2022-02-10 01:52:09">2022-02-10</time></span></div><div class="content">1、对象存活判断算法1）引用计数算法
在对象中添加一个引用计数器，每当有一个地方 引用它时，计数器值就加一；当引用失效时，计数器值就减一；任何时刻计数器为零的对象就是不可 能再被使用的。

这个算法原理简单，判断效率也高，但如果出现对象之间的相互引用(循环引用)，那么相应对象的引用计数器将永不为0，也就无法被回收掉，即使他们已经没有存活的意义。
2）可达性分析算法GC Root 也称为根对象，代表的是当前时刻仍然存活着的对象，可作为根对象的主要有以下几类：
① 在虚拟机栈中引用的对象，例如参数、局部变量、临时变量等；
② 在方法区中类静态属性(static 属性)引用的对象，例如 Java 类的引用类型静态变量；
③ 在方法区中常量引用的对象，例如字符串常量池(StringTable)里的引用(“ab”,”a”等等)；
④ 在本地方法栈中Native方法引用的对象；
⑤ JVM 内部引用对象，例如一些基本数据类型对应的对象，一些异常类对象等；
⑥ 所有被同步锁( synchronized ) 持有的对象；
⑦ 反映Java虚拟机内部情况的 JMXBean 、 JVMTI 中注册的回调、 ...</div></div></div><nav id="pagination"><div class="pagination"><a class="extend prev" rel="prev" href="/"><i class="fas fa-chevron-left fa-fw"></i></a><a class="page-number" href="/">1</a><span class="page-number current">2</span><a class="page-number" href="/page/3/#content-inner">3</a><span class="space">&hellip;</span><a class="page-number" href="/page/5/#content-inner">5</a><a class="extend next" rel="next" href="/page/3/#content-inner"><i class="fas fa-chevron-right fa-fw"></i></a></div></nav></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="card-info-avatar is-center"><img class="avatar-img" src="/img/avatar.jpg" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/><div class="author-info__name">h0ss</div><div class="author-info__description">一个苦逼后端仔的学习记录</div></div><div class="card-info-data"><div class="card-info-data-item is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">51</div></a></div><div class="card-info-data-item is-center"><a href="/tags/"><div class="headline">标签</div><div class="length-num">14</div></a></div></div><a class="button--animated" id="card-info-btn" target="_blank" rel="noopener" href="https://gitee.com/h0ss"><i class="fab fa-github"></i><span>Gitee仓库</span></a></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn card-announcement-animation"></i><span>公告</span></div><div class="announcement_content">Java后端技术栈语雀文档：https://www.yuque.com/oliver-wdtb1/java</div></div><div class="sticky_layout"><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2022/11/16/%E7%BB%99%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%E6%8F%90%E4%BA%86%E4%B8%AAPR/" title="给开源项目提了个PR">给开源项目提了个PR</a><time datetime="2022-11-15T17:28:40.000Z" title="发表于 2022-11-16 01:28:40">2022-11-16</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2022/09/03/%E3%80%90MySQL%E3%80%91InnoDB%E7%9A%84%E8%A1%8C%E6%A0%BC%E5%BC%8F/" title="【MySQL】InnoDB的行格式">【MySQL】InnoDB的行格式</a><time datetime="2022-09-02T18:17:38.000Z" title="发表于 2022-09-03 02:17:38">2022-09-03</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2022/08/21/%E3%80%90Debug%E3%80%91bitField-%E5%BC%95%E5%8F%91%E7%9A%84%E6%A0%88%E6%BA%A2%E5%87%BA%E6%8E%92%E9%94%99%E8%AE%B0/" title="【Debug】bitField 引发的栈溢出排错记">【Debug】bitField 引发的栈溢出排错记</a><time datetime="2022-08-20T18:10:40.000Z" title="发表于 2022-08-21 02:10:40">2022-08-21</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2022/07/16/%E3%80%90RPC%E3%80%91%E8%AF%A6%E8%A7%A3SPI%E6%9C%BA%E5%88%B6/" title="【RPC】详解SPI机制">【RPC】详解SPI机制</a><time datetime="2022-07-15T18:51:57.000Z" title="发表于 2022-07-16 02:51:57">2022-07-16</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2022/07/14/%E3%80%90Redis%E3%80%91%E9%87%8D%E8%A6%81%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%9F%BA%E7%A1%80/" title="【Redis】重要数据结构基础">【Redis】重要数据结构基础</a><time datetime="2022-07-13T17:22:08.000Z" title="发表于 2022-07-14 01:22:08">2022-07-14</time></div></div></div></div><div class="card-widget card-tags"><div class="item-headline"><i class="fas fa-tags"></i><span>标签</span></div><div class="card-tag-cloud"><a href="/tags/AppCube/" style="font-size: 1.1em; color: #999">AppCube</a> <a href="/tags/JVM/" style="font-size: 1.33em; color: #99a2af">JVM</a> <a href="/tags/Java/" style="font-size: 1.5em; color: #99a9bf">Java</a> <a href="/tags/LeetCode/" style="font-size: 1.21em; color: #999ea4">LeetCode</a> <a href="/tags/Linux/" style="font-size: 1.39em; color: #99a4b4">Linux</a> <a href="/tags/MySQL/" style="font-size: 1.44em; color: #99a7ba">MySQL</a> <a href="/tags/Mybatis/" style="font-size: 1.1em; color: #999">Mybatis</a> <a href="/tags/RPC/" style="font-size: 1.27em; color: #99a0a9">RPC</a> <a href="/tags/Redis/" style="font-size: 1.27em; color: #99a0a9">Redis</a> <a href="/tags/SQL/" style="font-size: 1.1em; color: #999">SQL</a> <a href="/tags/Spring/" style="font-size: 1.33em; color: #99a2af">Spring</a> <a href="/tags/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/" style="font-size: 1.1em; color: #999">正则表达式</a> <a href="/tags/%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86/" style="font-size: 1.1em; color: #999">组成原理</a> <a href="/tags/%E8%AE%A1%E7%BD%91/" style="font-size: 1.16em; color: #999b9e">计网</a></div></div><div class="card-widget card-archives"><div class="item-headline"><i class="fas fa-archive"></i><span>归档</span><a class="card-more-btn" href="/archives/" title="查看更多">
    <i class="fas fa-angle-right"></i></a></div><ul class="card-archive-list"><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2022/11/"><span class="card-archive-list-date">十一月 2022</span><span class="card-archive-list-count">1</span></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2022/09/"><span class="card-archive-list-date">九月 2022</span><span class="card-archive-list-count">1</span></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2022/08/"><span class="card-archive-list-date">八月 2022</span><span class="card-archive-list-count">1</span></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2022/07/"><span class="card-archive-list-date">七月 2022</span><span class="card-archive-list-count">4</span></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2022/06/"><span class="card-archive-list-date">六月 2022</span><span class="card-archive-list-count">10</span></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2022/05/"><span class="card-archive-list-date">五月 2022</span><span class="card-archive-list-count">1</span></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2022/04/"><span class="card-archive-list-date">四月 2022</span><span class="card-archive-list-count">1</span></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2022/03/"><span class="card-archive-list-date">三月 2022</span><span class="card-archive-list-count">1</span></a></li></ul></div><div class="card-widget card-webinfo"><div class="item-headline"><i class="fas fa-chart-line"></i><span>网站资讯</span></div><div class="webinfo"><div class="webinfo-item"><div class="item-name">文章数目 :</div><div class="item-count">51</div></div><div class="webinfo-item"><div class="item-name">已运行时间 :</div><div class="item-count" id="runtimeshow" data-publishDate="2021-02-14T16:00:00.000Z"></div></div><div class="webinfo-item"><div class="item-name">本站总字数 :</div><div class="item-count">129.9k</div></div><div class="webinfo-item"><div class="item-name">最后更新时间 :</div><div class="item-count" id="last-push-date" data-lastPushDate="2022-11-15T17:31:31.795Z"></div></div></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button id="go-up" type="button" title="回到顶部"><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><div class="js-pjax"></div><script defer="defer" id="fluttering_ribbon" mobile="false" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/canvas-fluttering-ribbon.min.js"></script><script id="canvas_nest" defer="defer" color="0,0,255" opacity="0.7" zIndex="-1" count="99" mobile="false" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/canvas-nest.min.js"></script><script id="click-heart" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/click-heart.min.js" async="async" mobile="false"></script><script id="click-show-text" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/click-show-text.min.js" data-mobile="false" data-text="爱国,敬业,诚信,友善,自由,平等,公正,法治,富强,民主,文明,和谐" data-fontsize="16px" data-random="false" async="async"></script></div></body></html>